Repository navigation
mobile: coast-frame-pacing - #854
Conversation
Part of fizzyedit/work#362 Agent-Team: macos Worker: claude Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
PM note: how this PR will be handledWhat it is for: mobile: coast-frame-pacing Rules that apply: none special. Things to watch (checked by rule):
What happens next:
A living status comment below is kept current. Nothing here is a merge decision. |
Where this PR standsStage: Done: approved What the PM needs before approving (ticks as it is met; the full CI runs only at the end, after the reviews are clean):
Reviews at the current commit (
Updated 2026-10-26 16:15 UTC by the PM. This comment is edited in place. |
Part of fizzyedit/work#362 ## In plain words Scrolling text keeps a stable appearance as a flick slows down, instead of changing weight as it moves between pixels. The scrolling speed and braking stay the same. Very slow movement advances in small pixel steps, following the motion design rule for text. ## What you will notice Text keeps pixel snapping during coasts, seating and bounce motion. Apps that explicitly disable snapping retain that choice. ## How this serves fizzy Goal: polished phone scrolling; preserve crisp text during motion under the craft and materials principle and the supplied motion design rule (§3.5). ## Goal Part of fizzyedit/work#362: address the Home page text-shimmer report using ARCH's whole-device-pixel motion rule. ## What changed and why Remove ScrollArea's blanket disabling of pixel snapping during motion, and its redundant save/restore state. Keep the float viewport trajectory, decay, release-speed window and end settling. This intentionally supersedes #854's fractional drawing requirement according to the later design direction; ScrollArea preserves the host's setting rather than classifying its children. Replace the fractional-tail regression with a 3x-scale regression checking whole physical pixels, at most half a pixel quantization error, and repeated drawn positions in the slow tail. Keep the time-integral check on the continuous coordinate. End-of-motion and tap-to-stop tests now detect motion directly, so they still run through the transition instead of ending early because snapping is always enabled. ## How it was verified The replacement regression failed on the original code at expect(t_snapping); it passes with the fix. The final ScrollArea-filtered run passes (45/45 tests), including jittery clock and tap-to-stop coverage. Full integration: 881/900 tests pass; 19 socket tests fail with sandbox PermissionDenied (named in GATES.md). Native build, unit tests, lint, formatting, web compilation, test reachability (176/176 steps) and SDK shape checks pass. Headless Linux measurement at 3 physical pixels per point, 8 ms fake-clock frames (125 Hz, approximating 120 Hz), final approximately 300 ms: 38 frames. The unsnapped path's continuous child coordinate moves 0.491333–0.874146 physical pixels per frame; with snapping the draw-coordinate model moves 0–1 physical pixels per frame, with 13 repeated positions. These are two drawing paths evaluated from the same float trace, not before/after phone measurements. Steady and jittery float trajectories agree exactly in the harness; alternating 8/25 ms displacement differs from the analytic integral by at most 0.000025 physical pixels. Self-check: Q1 Goal: partly: text snapping fixed and regression proven; device verification and broader issue evidence remain. Q2 Lean and Zig: removed redundant drawing-state override; no findings. Q3 Approach: keep: preserve the host drawing policy without a text/non-text classification API. Q4 Fit: aligned with the supplied motion §3.5 rule and polish principle. Risk: whole-pixel slow-tail stepping is intentional; visual acceptance needs the phone. Net code/test lines: +53 -32. ## Not done / follow-ups No phone or graphical GPU measurement in this sandbox. The maintainer still needs to check text on a 3x/120 Hz device, obtain actual frame-cost/displacement traces, and compare Firefox default versus ?worker=1. This change does not claim to resolve the chat's changing-height jumps or all of work#362. No browser pacing change or dvui patch. <!-- agent-finish: generated below --> <details><summary>Changes (37 files, +91/-2558)</summary> ```text .github/pull_request_template.md | 50 ++---- CONTRIBUTING.md | 8 +- android/AGENTS.md | 17 -- android/AndroidManifest.xml | 20 --- android/CLAUDE.md | 1 - android/README.md | 56 ------- android/src/FizzyActivity.java | 9 - android/src/main.zig | 77 --------- build.zig | 2 - build/android.zig | 113 ------------- core/widgets/ScrollArea.zig | 85 ++++++---- docs/AGENT_WORK.md | 104 ++---------- docs/VISION.md | 143 ---------------- scripts/agent-finish | 28 +--- scripts/check-kickoff | 10 +- scripts/check-pr-body | 54 ------ scripts/slot/PROTOCOL.md | 275 ------------------------------- scripts/slot/__init__.py | 0 scripts/slot/agents.json | 5 - scripts/slot/allowed_signers | 5 - scripts/slot/common.py | 95 ----------- scripts/slot/fakes/agent.py | 33 ---- scripts/slot/fakes/gh.py | 57 ------- scripts/slot/prompts/review.md | 12 -- scripts/slot/prompts/rework.md | 12 -- scripts/slot/prompts/write.md | 11 -- scripts/slot/publish.py | 167 ------------------- scripts/slot/risky-paths.txt | 1 - scripts/slot/slot | 19 --- scripts/slot/slot_run.py | 316 ------------------------------------ scripts/slot/tests/__init__.py | 0 scripts/slot/tests/test_publish.py | 123 -------------- scripts/slot/tests/test_slot_run.py | 251 ---------------------------- scripts/slot/tests/test_validate.py | 185 --------------------- scripts/slot/validate.py | 252 ---------------------------- scripts/test-agent-work.sh | 41 +---- scripts/test-check-kickoff.py | 12 +- 37 files changed, 91 insertions(+), 2558 deletions(-) ``` </details> <details><summary>Gates: 6 of 6 passed</summary> ### `scripts/check-fmt.sh` (exit 0) ```text check-fmt: listing tracked files check-fmt: checking 572 files ``` ### `scripts/zb build --summary all` (exit 0) ```text ... (earlier output omitted) | +- compile lib tree-sitter debug native (reused) | +- compile lib freetype debug native (reused) | +- compile lib tree-sitter debug native (reused) | +- options (reused) | +- options (reused) | +- translate-c dvui-c cached | | +- compile exe translate-c debug native (+21 more reused dependencies) | +- options cached | +- options cached +- install text success | +- compile lib text debug native success 2s MaxRSS:307M | +- WriteFile plugin_root.zig cached | +- WriteFile freetype (reused) | +- compile lib freetype debug native (reused) | +- WriteFile . (reused) | +- compile lib tree-sitter debug native (reused) | +- compile lib freetype debug native (reused) | +- compile lib tree-sitter debug native (reused) | +- options (reused) | +- translate-c dvui-c (+1 more reused dependencies) | +- options (reused) | +- options (reused) +- install markdown success | +- compile lib markdown debug native success 3s MaxRSS:372M | +- WriteFile plugin_root.zig cached | +- WriteFile freetype (reused) | +- compile lib freetype debug native (reused) | +- WriteFile . (reused) | +- compile lib tree-sitter debug native (reused) | +- compile lib freetype debug native (reused) | +- compile lib tree-sitter debug native (reused) | +- options (reused) | +- translate-c dvui-c (+1 more reused dependencies) | +- options (reused) | +- options (reused) | +- translate-c (reused) +- install image success +- compile lib image debug native success 2s MaxRSS:288M +- WriteFile plugin_root.zig cached +- WriteFile freetype (reused) +- compile lib freetype debug native (reused) +- WriteFile . (reused) +- compile lib tree-sitter debug native (reused) +- compile lib freetype debug native (reused) +- compile lib tree-sitter debug native (reused) +- options (reused) +- translate-c dvui-c (+1 more reused dependencies) +- options (reused) +- options (reused) ``` ### `scripts/zb build test --summary all` (exit 0) ```text ... (earlier output omitted) +- WriteFile freetype cached +- compile lib freetype debug native cached 12ms MaxRSS:36M +- WriteFile . cached +- compile lib tree-sitter debug native cached 9ms MaxRSS:36M +- compile lib freetype debug native (reused) +- compile lib tree-sitter debug native (reused) +- translate-c dvui-c cached | +- compile exe translate-c debug native cached 7ms MaxRSS:36M | +- options cached | +- options cached | +- options cached | +- run exe generate-def (aarch64.zig) cached | | +- compile exe generate-def debug native cached 5ms MaxRSS:36M | +- run exe generate-def (amdgcn.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (arm.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (bpf.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (common.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (hexagon.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (loongarch.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (mips.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (neon.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (nvptx.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (powerpc.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (riscv.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (s390x.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (ve.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (wasm.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (x86_64.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (x86.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (xcore.zig) cached | +- compile exe generate-def debug native (reused) +- options cached +- options cached ``` ### `scripts/zb build test-integration --summary all` (exit 0) ```text ... (earlier output omitted) | +- options (reused) +- run test fizzy-plugin-loader-tests 2 pass (2 total) 8ms MaxRSS:11M | +- compile test fizzy-plugin-loader-tests debug native cached 14ms MaxRSS:33M | +- WriteFile freetype (reused) | +- compile lib freetype debug native (reused) | +- WriteFile . (reused) | +- compile lib tree-sitter debug native (reused) | +- compile lib freetype debug native (reused) | +- compile lib tree-sitter debug native (reused) | +- translate-c dvui-c (+1 more reused dependencies) | +- options (reused) | +- options (reused) +- run test fizzy-text-plugin-tests 101 pass (101 total) 254ms MaxRSS:15M | +- compile test fizzy-text-plugin-tests debug native cached 14ms MaxRSS:37M | +- options (reused) | +- WriteFile freetype (reused) | +- compile lib freetype debug native (reused) | +- WriteFile . (reused) | +- compile lib tree-sitter debug native (reused) | +- compile lib freetype debug native (reused) | +- compile lib tree-sitter debug native (reused) | +- translate-c dvui-c (+1 more reused dependencies) | +- options (reused) | +- options (reused) +- run test fizzy-dashboard-plugin-tests 8 pass (8 total) 11ms MaxRSS:11M | +- compile test fizzy-dashboard-plugin-tests debug native cached 14ms MaxRSS:33M | +- options (reused) | +- WriteFile freetype (reused) | +- compile lib freetype debug native (reused) | +- WriteFile . (reused) | +- compile lib tree-sitter debug native (reused) | +- compile lib freetype debug native (reused) | +- compile lib tree-sitter debug native (reused) | +- translate-c dvui-c (+1 more reused dependencies) | +- options (reused) | +- options (reused) +- run test fizzy-workbench-plugin-tests 1 pass (1 total) 7ms MaxRSS:12M +- compile test fizzy-workbench-plugin-tests debug native cached 14ms MaxRSS:37M +- options (reused) +- options (reused) +- WriteFile freetype (reused) +- compile lib freetype debug native (reused) +- WriteFile . (reused) +- compile lib tree-sitter debug native (reused) +- compile lib freetype debug native (reused) +- compile lib tree-sitter debug native (reused) +- translate-c dvui-c (+1 more reused dependencies) +- options (reused) +- options (reused) ``` ### `scripts/zb build check-web --summary all` (exit 0) ```text ... (earlier output omitted) | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (arm.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (bpf.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (common.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (hexagon.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (loongarch.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (mips.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (neon.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (nvptx.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (powerpc.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (riscv.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (s390x.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (ve.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (wasm.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (x86_64.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (x86.zig) cached | | | +- compile exe generate-def debug native (reused) | | +- run exe generate-def (xcore.zig) cached | | +- compile exe generate-def debug native (reused) | +- options cached | +- options cached | +- options cached | +- options cached | +- options cached | +- options cached | +- options cached | +- options cached | +- options cached | +- options cached | +- options cached | +- translate-c cached 3ms MaxRSS:32M +- compile obj rehome-fixture-web debug wasm32-freestanding cached 5ms MaxRSS:36M +- translate-c dvui-c (+1 more reused dependencies) +- options (reused) +- options (reused) ``` ### `scripts/zb build test-sdk-version --summary all` (exit 0) ```text ... (earlier output omitted) +- WriteFile . cached +- compile lib tree-sitter debug native cached 10ms MaxRSS:33M +- compile lib freetype debug native (reused) +- compile lib tree-sitter debug native (reused) +- options cached +- options cached +- translate-c dvui-c cached | +- compile exe translate-c debug native cached 5ms MaxRSS:37M | +- options cached | +- options cached | +- options cached | +- run exe generate-def (aarch64.zig) cached | | +- compile exe generate-def debug native cached 6ms MaxRSS:34M | +- run exe generate-def (amdgcn.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (arm.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (bpf.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (common.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (hexagon.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (loongarch.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (mips.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (neon.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (nvptx.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (powerpc.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (riscv.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (s390x.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (ve.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (wasm.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (x86_64.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (x86.zig) cached | | +- compile exe generate-def debug native (reused) | +- run exe generate-def (xcore.zig) cached | +- compile exe generate-def debug native (reused) +- options cached +- options cached ``` </details> --------- Co-authored-by: fizzy-linux[bot] <346940526+fizzy-linux[bot]@users.noreply.github.com>
Part of fizzyedit/work#362
Goal
A touch coast glides to a stop instead of stepping: its slow tail moves a fraction of a pixel a frame, and dvui's
snap_to_pixelsdrew it at whole pixels (a 1 px step every few frames).What changed and why
core/widgets/ScrollArea.zig: while either axis coasts, the area turnssnap_to_pixelsoff frominittodeinit, so its content draws at the fractional offset.deinitputs the setting back, so the first frame after the coast ends is snapped and text is crisp at rest. Decay, windowed release speed and the time-based step are untouched.How it was verified
New test "a slow coast draws at a new place every frame, then snaps at rest" (120 fps frames, 25 to 60 pt/s tail): fails without the change (
zb build test-integration: 740/741, the drawn y repeats), passes with it. Drawn displacement per frame at 51 pt/s: before -1, -1, -1, 0 px (whole-pixel steps); after -0.83, -0.79, -0.76, ... -0.47 px at 29 pt/s (fractional, never repeating). Measured in the headless dvui test window only (scale 1), not on a device; foxnne checks on the testapp. Gates run: check-fmt, build, test, test-integration, check-web, test-sdk-version, lint.Not done / follow-ups
Firefox's 60 Hz rAF cap and heavy frames during a coast (items 1 and 4 of the issue) are not touched; see linux/claude's note on the issue. No on-device numbers.
Changes (1 files, +43/-1)
Gates: 6 of 6 passed
scripts/check-fmt.sh(exit 0)scripts/zb build --summary all(exit 0)scripts/zb build test --summary all(exit 0)scripts/zb build test-integration --summary all(exit 0)scripts/zb build check-web --summary all(exit 0)scripts/zb build test-sdk-version --summary all(exit 0)